
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "DuLink.h"      
#include "DuLink.c"      
#include "Stack.h"       
#include "Stack.c"       
#include "file_wr.h"     
#include "file_wr.c"     
#include "text_operations.c" 
#include "text_operations.h" 

//显示文本编辑器菜单选项
void menu()
{
    printf("======== Text Editor Menu ========\n");
    printf("0. Insert Line\t1. Delete Line\n");
    printf("2. Modify Line\t3. Undo\n");
    printf("4. Redo\t\t5. Print All Lines\n");
    printf("6. Load file\t7. Save file\n");
    printf("8. Find text\t9. Replace text\n");
    printf("10. Copy line\t11. Paste line\n");
    printf("12. Cut text\t13. Exit\n");
    printf("==================================\n");
}   

//主函数
int main()
{
    DuLinkList L;  
    PLinkStack undoStack = createNullStack_link();  
    PLinkStack redoStack = createNullStack_link();  
    
    if (!InitDL(&L)) 
    {
        printf("Failed to initialize list!\n");
        return -1;
    }
    
    int choice;           
    char* copy_str = NULL; 

    while(1)
    {
        menu();  // 显示菜单
        printf("Enter your choice: ");
        scanf("%d", &choice);
        while(getchar() != '\n'); 
        switch(choice)
        {
            case 0:  // 插入行
            {
                printf("Execute insert line function\n"); 
                printf("Enter position to insert: ");
                int position;
                scanf("%d", &position);
                while(getchar() != '\n');
                printf("Enter text to insert: ");
                char input[100];
                fgets(input, sizeof(input), stdin);
                input[strcspn(input, "\n")] = '\0'; 
                // 插入行
                Insert_DL(&L, position, input);
                
                EditAction *action = malloc(sizeof(EditAction));
                if (!action) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action->operation ='I';         // 插入操作
                action->line = position;
                action->pos=0;
                action->oldText = NULL;
                action->newText = strdup(input);
                Push_LinkStack(undoStack, action);
                destroyStack_link(redoStack);   // 清空重做栈
                break;
            }    
            case 1:  // 删除行
            {
                printf("Execute delete line function\n");  
                printf("Enter position to delete: ");
                int position;
                scanf("%d", &position);
                while(getchar() != '\n'); 
                
                // 删除指定行
                Elemtype deleted = Delet_DL(&L, position);
                if (!deleted) 
                {
                    printf("Invalid position\n");
                    break;
                }
                printf("Deleted line: %s\n", deleted);
                
                // 记录删除操作用于撤销
                EditAction *action = (EditAction*)malloc(sizeof(EditAction));
                if (!action) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action->operation = 'D';        // 删除操作
                action->line = position;
                action->pos=0;
                action->oldText = strdup(deleted);
                action->newText = NULL;
                Push_LinkStack(undoStack, action);
                free(deleted);  
                destroyStack_link(redoStack);   // 清空重做栈
                break;
            }    
            case 2:  // 修改行
            {
                printf("Execute modify line function\n");  
                printf("Enter position to modify: ");
                int position;
                scanf("%d", &position);
                while(getchar() != '\n');
                
                // 先删除再插入实现修改
                Elemtype delete = Delet_DL(&L, position);
                if (!delete) 
                {
                    printf("Invalid position\n");
                    break;
                }
                printf("Enter new text: ");
                char input[100];
                fgets(input, sizeof(input), stdin);
                input[strcspn(input, "\n")] = '\0';
                Insert_DL(&L, position, input);
                
                // 记录修改操作用于撤销
                EditAction *action = malloc(sizeof(EditAction));
                if (!action) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action->operation ='M';         // 修改操作
                action->line = position;
                action->pos=0;
                action->oldText = strdup(delete);
                action->newText = strdup(input);
                if (delete) 
                {
                    free(delete);  
                }
                Push_LinkStack(undoStack, action);
                destroyStack_link(redoStack);   // 清空重做栈
                break;
            }
            case 3:  // 撤销操作
            {
                printf("Execute undo function\n");
                if (!undoStack || !undoStack->top) 
                {
                    printf("Nothing to undo.\n");
                    break;
                }
                
                EditAction *top = Pop_LinkStack(undoStack);
                if(top != NULL)
                {
                    // 根据操作类型执行相应的撤销操作
                    if(top->operation == 'I')  // 撤销插入
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if (deleted) 
                        {
                            free(deleted);
                        }
                        printf("Undo Insert Operation Successfully\n");
                    }               
                    else if(top->operation == 'D')  // 撤销删除
                    {
                        Insert_DL(&L, top->line, top->oldText);
                        printf("Undo Delete Operation Successfully\n");
                    }
                    else if(top->operation == 'M')  // 撤销修改
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted)
                        {
                            free(deleted);
                        }

                        Insert_DL(&L, top->line, top->oldText);
                        printf("Undo Modify Operation Successfully\n");
                    }
                    else if(top->operation == 'R')  // 撤销替换
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted)
                        {
                            free(deleted);
                        }
                        Insert_DL(&L, top->line, top->oldText);
                        printf("Undo Replace Operation Successfully\n");
                    }
                    else if(top->operation == 'P')  // 撤销粘贴
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted)
                        {
                            free(deleted);
                        }
                        if(top->oldText!= NULL)
                        {
                            Insert_DL(&L,top->line,top->oldText);
                        }
                        printf("Undo Paste Operation Successfully\n");
                    }
                    else if(top->operation == 'X')  // 撤销剪切的删除
                    {
                        printf("Undoing cut from line %d\n", top->line);
                        DuLinkList p = L->next;
                        int currentLine = 1;
                        
                        while (p && currentLine < top->line)
                        {
                            currentLine++;
                            p = p->next;
                        }
                        
                        if (p && p->info)
                        {
                            free(p->info);
                            p->info = strdup(top->oldText);
                            printf("Restored original text at line %d: %s\n", top->line, p->info);
                        }
                        printf("Undo Cut Operation Successfully\n");
                    }
                    else if(top->operation == 'V')  // 撤销剪切的粘贴
                    {
                        printf("Undoing paste at line %d\n", top->line);
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted) free(deleted);
                        
                        if(top->oldText != NULL)
                        {
                            Insert_DL(&L, top->line, top->oldText);
                        }
                         printf("Undo Paste Operation Successfully\n");
                    }
                }
                // 将撤销的操作放入重做栈中
                Push_LinkStack(redoStack, top);
                freeEditActionStrings(top);
                free(top);
                break;
            }    
            case 4:  // 重做操作
            {
                printf("Execute redo function\n");
                // 检查是否有可重做的操作
                if (!redoStack || !redoStack->top) 
                {
                    printf("Nothing to redo.\n");
                    break;
                }
                
                EditAction *top = Pop_LinkStack(redoStack);
                if(top != NULL)
                {
                    // 根据操作类型执行相应的重做操作
                    if(top->operation == 'I')  // 重做插入
                    {
                        Insert_DL(&L, top->line, top->newText);
                        printf("Redo Insert Operation Successfully\n");
                    }               
                    else if(top->operation == 'D')  // 重做删除
                    {
                        Elemtype delete=Delet_DL(&L, top->line);
                        if(delete) free(delete);
                        printf("Redo Delete Operation Successfully\n");
                    }
                    else if(top->operation == 'M')  // 重做修改
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted) free(deleted);
                        Insert_DL(&L, top->line, top->newText);
                        printf("Redo Modify Operation Successfully\n");
                    }
                    else if(top->operation == 'R')  // 重做替换
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted) free(deleted);
                        Insert_DL(&L, top->line, top->newText);
                        printf("Redo Replace Operation Successfully\n");
                    }
                    else if(top->operation == 'P')  // 重做粘贴
                    {
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted) free(deleted);
                        if(top->newText != NULL)
                        {
                            Insert_DL(&L, top->line, top->newText);
                        }
                        printf("Redo Paste Operation Successfully\n");
                    }
                    else if(top->operation == 'X')  // 重做剪切
                    {
                        printf("Redoing cut at line %d\n", top->line);
                        
                        DuLinkList p = L->next;
                        int currentLine = 1;
                        
                        while (p && currentLine < top->line)
                        {
                            currentLine++;
                            p = p->next;
                        }
                        
                        if (p && p->info)
                        {
                            free(p->info);
                            p->info = strdup(top->newText);
                            printf("Re-applied cut at line %d: %s\n", top->line, p->info);
                        }
                        printf("Redo Cut Operation Successfully\n");
                    }
                    else if(top->operation == 'V')  // 重做粘贴
                    {
                        printf("Redoing paste at line %d\n", top->line);
                        // 重新执行粘贴：删除当前文本，插入粘贴的文本
                        Elemtype deleted = Delet_DL(&L, top->line);
                        if(deleted) free(deleted);
                        
                        if(top->newText != NULL)
                        {
                            Insert_DL(&L, top->line, top->newText);
                        }
                        printf("Redo Paste Operation Successfully\n");
                    }
                    
                    Push_LinkStack(undoStack, top);
                    freeEditActionStrings(top);
                    free(top);
                }
                break;
            }
    
            case 5:  // 打印所有行
            {
                printf("Execute print all lines function\n");
                Print_DL(L);
                break;
            }    
            case 6:  // 读取文件
            {
                printf("Execute save read function\n");
                printf("Enter filename to read: ");
                char path[100];
                fgets(path, sizeof(path), stdin);
                path[strcspn(path, "\n")] = '\0';
                file_read(path, &L);
                break;
            }    
            case 7:  // 保存文件
            {   
                printf("Execute write file function\n");
                printf("Enter filename to write: ");
                char write_path[100];
                fgets(write_path, sizeof(write_path), stdin);
                write_path[strcspn(write_path, "\n")] = '\0';
                file_append(write_path,&L);
                break;
            }    
            case 8:  // 查找文本
            {
                printf("Execute search text function\n");
                printf("Enter search text:");
                char str[100];
                fgets(str, sizeof(str), stdin);
                str[strcspn(str, "\n")] = '\0'; 
                int count=Search_Text(&L,str);
                printf("search text counts are %d",&count);
                break;
            }    
            case 9:  // 替换文本
            {
                printf("Execute replace text function\n");
                int count=0;
                char old_text[100];
                while(count==0)
                {
                    printf("Enter old text:");
                    fgets(old_text, sizeof(old_text), stdin);
                    old_text[strcspn(old_text, "\n")] = '\0'; 
                    count=Search_Text(&L,old_text);
                }
                printf("search text counts are %d\n", count); 
                printf("Enter new text:");
                char new_text[100];
                fgets(new_text, sizeof(new_text), stdin);
                new_text[strcspn(new_text, "\n")] = '\0'; 
                Replace_text(&L,old_text,new_text,undoStack,redoStack);
                break;
            }    
            case 10:  // 复制文本
            {
                printf("Execute copy line function\n");  
                printf("Enter line number to copy:");
                int line;
                scanf("%d",&line);
                while(getchar() != '\n'); 
                printf("Enter startpos number to copy:");
                int pos;
                scanf("%d",&pos);
                while(getchar() != '\n'); 
                printf("Enter line length to copy:");
                int length;
                scanf("%d",&length);
                while(getchar() != '\n'); 
                copy_str = Copy_DL(&L, line, pos, length);
                if (!copy_str) 
                {
                    printf("Copy failed or returned no text.\n");
                }
                break;
            }
                
            case 11:  // 粘贴文本
            {
                printf("Execute paste line function\n");  
                printf("Enter line number to paste:");
                int line;
                scanf("%d",&line);
                while(getchar() != '\n');
                
                printf("Enter startups to paste, if want a new line then enter -1:");
                int startups;
                scanf("%d",&startups);
                while(getchar() != '\n');
                
                if (copy_str == NULL) 
                {
                    printf("No text to paste! Please copy first.\n");
                    break;
                }
                Elemtype old_text = NULL;
                if(startups == -1)
                {
                    Insert_DL(&L, line, copy_str);
                }
                else
                {
                    old_text = Search_Line(L, line);
                    if (old_text == NULL) 
                    {
                        printf("Line %d not found!\n", line);
                        break;
                    }
                    
                    old_text = strdup(old_text);
                    Paste_DL(&L, line, startups, copy_str);
                }
                Elemtype new_text=Search_Line(L,line);
                EditAction *action = malloc(sizeof(EditAction));
                if (!action) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action->operation = 'P';
                action->line = line;
                action->pos=0;
                action->oldText = old_text; 
                action->newText = new_text ? strdup(new_text) : NULL;
                Push_LinkStack(undoStack, action);
                destroyStack_link(redoStack);
                break;
            }
                
           
            case 12:  // 剪切文本
            {
                printf("Execute cut text function\n");
                // 剪切操作
                printf("Enter line number to cut:");
                int line;
                scanf("%d",&line);
                while(getchar() != '\n'); 
                Elemtype old_text1=Search_Line(L,line);
                printf("Enter startpos number to cut:");
                int pos;
                scanf("%d",&pos);
                while(getchar() != '\n'); 
                printf("Enter line length to cut:");
                int length;
                scanf("%d",&length);
                while(getchar() != '\n'); 
                copy_str = Delete_cut(&L, line, pos, length);
                Elemtype new_text1=Search_Line(L,line);
                printf("Cut new text is %s\n",new_text1);
                EditAction *action1 = malloc(sizeof(EditAction));
                if (!action1) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action1->operation = 'X';
                action1->line = line;
                action1->pos=0;
                action1->oldText = strdup(old_text1); 
                action1->newText = strdup(new_text1);
                Push_LinkStack(undoStack, action1);
                
                // 粘贴操作
                printf("Enter line number to cut_paste:");
                int line_paste;
                scanf("%d",&line_paste);
                while(getchar() != '\n');
                printf("Enter startups to cut_paste, if want a new line then enter -1:");
                int startups;
                scanf("%d",&startups);
                while(getchar() != '\n');
                if (copy_str == NULL) 
                {
                    printf("No text to cut! Please cut first.\n");
                    break;
                }
                Elemtype old_text2=NULL;
                if(startups == -1)
                {
                    Insert_DL(&L, line_paste, copy_str);
                }
                else
                {
                    old_text2 = Search_Line(L, line_paste);
                    if (old_text2 == NULL) 
                    {
                        printf("Line %d not found!\n", line_paste);
                        break;
                    }
                    
                    old_text2 = strdup(old_text2);
                    Paste_DL(&L, line_paste, startups, copy_str);
                }
                Elemtype new_text2=Search_Line(L,line_paste);
                EditAction *action2 = malloc(sizeof(EditAction));
                if (!action2) 
                {
                    fprintf(stderr, "Memory allocation failed for undo action\n");
                    break;
                }
                action2->operation = 'V';
                action2->line = line_paste;
                action2->pos=0;
                action2->oldText = strdup(old_text2); 
                action2->newText = new_text2 ? strdup(new_text2) : NULL;
                Push_LinkStack(undoStack, action2);
                destroyStack_link(redoStack);
                break;
            } 

            case 13:  // 退出程序
            {
                printf("Program exit\n");  
                // 释放所有分配的资源
                Destroy_DL(&L);
                destroyStack_link(undoStack);
                destroyStack_link(redoStack);
                return 0;
            }  
            default:  // 处理无效输入
            {
                printf("Invalid selection! Please re-enter.\n"); 
            }
        }
    }
    
    return 0;
}